home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Deutsche Edition 1
/
Deutsche Edition 1.iso
/
amok
/
amok_lha
/
amok10.lha
/
SuperLists1.3
/
SuperLists.dok
< prev
next >
Wrap
Text File
|
1993-08-15
|
17KB
|
350 lines
Dokumentation zu "SuperLists" Version 1.3
Autor: Nicolas Benezan, Postwiesenstr.2, 7000 Stuttgart 60
Unterstützung von Text-Listen mit Scroll-Gadgets
Einleitung
----------
SuperLists vereinfacht die Programmiering von Scrollfähigen Textlisten,
wie sie z.B. in Auswahlrequestern Verwendung finden. Es werden
Proportional- und Einzelschrittgadgets in X- und/oder Y-Richtung
unterstützt.
Inzwischen gibt es auch das Modul FileRequest (mit Demo), das ein gutes
Beispiel für die Verwendung von SuperLists ist.
Neu: Version 1.3
----------------
Bei der neuen Version kann auf Wunsch das horizontale Scrollgadget
weggelassen werden. Es ist auch möglich, mit Hilfe der Prozedur-
variablen AllocProc und DeallocProc eine eigene Speicherverwaltung
einzubinden. Darüberhinaus ist man jetzt nicht mehr an den Entry-
RECORD gebunden sondern kann sich mit
TYPE ExtEntry=RECORD
Node:MinEntry;
Data:IrgendeinTyp;
END;
eigene Eintragstypen konstruieren.
Neu ist auch die Prozedur ClearList().
So wird's gemacht
-----------------
Bevor man eine SuperList erzeugt, sollte man sich über folgendes im
Klaren sein:
* In welchem Window(-rastport) oder Requester(-rastport) soll die
Liste angezeigt werden
* Welche Hintergrundfarbe hat die Liste
* Wie sollen die Proportionalgadgets für vertikales und (falls
erwünscht) horizontales Srolling aussehen
* Wo und wie groß soll die Liste im Window (Requester) angezeigt
werden
* Welche Daten hat der zu dem verwendeten RastPort gehörige
Zeichensatz (Achtung, es darf keine Proportionalschrift sein)
* Welcher Ausschnitt soll voreinstellungsgemäß angezeigt werden
Bei der Version kann nun auch gewählt werden, ob die Liste nur vertikal
oder vertikal und horizontal gescrollt werden soll.
Erzeugen der Scrollgadgets
--------------------------
Jede SuperList benötigt ein oder zwei Proportionalgadgets, eines für
das vertikale Scrolling und optional ein zweites für die horizontale
Richtung. Diese Gadgets müssen erzeugt werden, bevor die Liste initiali-
siert wird. Es wird hier auf eine Beschreibung, wie dies geschieht,
verzichtet. Dies kann man zB. im "Intuition Reference Manual" nachlesen.
Initialisieren der Liste
------------------------
Eine SuperList besteht aus einem Listenkopf (SuperList-RECORD) und null
oder mehreren Einträgen (Entry-RECORDs). Der Listenkopf enthält Parameter,
die das Aussehen der Liste beschreiben, und solche, die vom SuperList-
Modul zur Verwaltung der Liste benötigt werden, sowie eine Exec.List zur
Verwaltung der Einträge. Ein Eintrag enthält einen Exec.Node zur
Verknüpfung der Einträge untereinander und den eigentlichen Text (in
Entry.node.name) sowie Parameter, die das Aussehen des Textes beschreiben
(Farbe, DrawMode).
Bevor die Liste das erste mal verwendet werden kann, müssen folgende
Paramter in der SuperList-Struktur initialisiert werden:
* rastPort - Zeiger auf den RastPort des Windows oder Requesters, in
dem die Liste angezeigt werden soll.
* backPen - Hintergrundfarbe der Liste
* propY - Zeiger auf das Proportionalgadget für vertikales Scrolling
* propX - Zeiger auf das Gadget für horizontales Scrolling falls dies
nicht erwünscht ist, sollte PropX auf NIL gesetzt werden
* leftEdge - linker Rand der Listenanzeigefläche relativ zum linken
Rand des Windows oder Requesters (Einheit: Pixel)
* topEdge - oberer Rand relativ zum Rand des Windows/Requesters
* width - Breite der Anzeigefläche (Einheit: Pixel), muß mindestens so
groß wie FontXsize+1 sein (s. unten)
* height - Höhe der Anzeigefläche, muß mindestens FontYsize sein
* FontXsize - Breite eines Zeichens in Pixel (kein Proportional-
schriftsatz!)
* FontYsize - Höhe einer Textzeile in Pixel(muß nicht unbedingt mit
der Höhe eines Zeichens übereinstimmen, wenn zB. zusätzlicher
Zeilenabstand erwünscht ist)
* FontBaseLine - besagt, auf welcher Höhe die Grundlinie der Zeichen
innerhalb einer Zeile liegen soll, sollte ungefähr gleich dem
baseLine-Paramter des Fonts gesetzt werden
* dispRow - Nummer des ersten Eintrags (Zeile) des zuerst
anzuzeigenden Ausschnitts (0 ist der erste Eintrag)
* dispColumn - Nummer der ersten Spalte des Ausschnitts (0 zeigt ab
der ersten Spalte)
ist kein horizontales Scrolling vorgesehen, sollte dieses Feld immer 0
sein
* Die Exec.List muß initialisiert werden. Dies geschieht am besten mit
ExecSupport.NewList(ADR(SuperList.list); .
Alle anderen Felder sollten nie verändert werden, sie dienen der internen
Verwaltung. Es ist aber vielleich manchmal interessant, sie zu lesen,
deshalb hier ihre Bedeutungen:
* rows - Anzahl der vorhandenen Einträge (Zeilen)
* columns - Anzahl der Spalten = Länge des längsten Eintrags (in
Zeichen, nicht in Pixel), nur bei eingeschltetem horizontalem
Scrolling definiert
* topEntry - Zeiger auf den Node des obersten angezeigten Eintrags
* bottomEntry - Zeiger auf den untersten angezeigten Eintrag
(Vorsicht: Falls keine Einträge vorhanden sind, müssen top- und
bottomEntry nicht unbedingt NIL sein. Diese Zeiger sollten möglichst
nicht für eigene Zwecke verwendet werden.)
* effWidth - Breite der Anzeigefläche in Zeichen (nicht in Pixel)
* effHeight - Höhe in Zeichen
Nachdem alles ordnungsgemäß initialisiert ist, wird RethinkList(
SuperListPtr, NewList) aufgerufen, wobei SuperListPtr ein Zeiger auf
den SuperList-RECORD und NewList eine von SuperLists exportierte
Konstante ist (newList/oldList). Um den aktuellen Ausschnitt der Liste
anzuzeigen, verwendet man RefreshList(SuperListPtr). Man kann die Liste
jetzt mit den Prozeduren ScrollList, InsertEntry, RemoveEntry, GetEntry,
SetProp, GetProp, ClickRow, MakeEntry, RedrawEntry, RethinkList und
RefreshList bearbeiten.
RefreshList
-----------
Diese Prozedur wird benötigt, um die Paramter zur interenen Verwaltung
im Listenkopf neu zu berechnen. Normalerweise werden diese beim Aufruf
von Prozeduren wie zB. InsertEntry automatisch aktualisiert. Es ist
jedoch manchmal nötig, einige Parameter "von Hand" zu ändern, wenn zB.
der Benutzer die Windowgröße verändert hat, und sich damit auch die
Anzeigefläche der Liste verändert. Um das SuperLists-Modul davon in
Kenntnis zu setzen, daß Parameter verändert wurden, sodaß es seine
internen Parameter neu be
echnen kann, wird RethinkList verwendet. Der Parameter New (newList
oder oldList) besagt, inwieweit die Listenparameter rekonstruiert werden
müssen. RethinkList(...,oldList) wird verwendet, wenn die Veränderung nur
die Anzeigefläche betrifft (zB. Höhe, Breite, Zeichensatz usw.). Die
Ausführungszeit ist im Gegensatz zu RethinkList(...,newList) relativ
kurz. Bei letzterem wird nämlich die ganze Liste der Einträge durch-
gegangen und Zeilen und Spalten werden neu gezählt. Dies ist notwendig,
wenn die Einträge mit anderen Prozeduren als die von SuperLists
bearbeitet wurden, sodaß sich die Texte der Einträge verändert haben,
oder Eiträge entfernt oder hinzugefügt wurden. Ein weiterer Fall ist
das Erzeugen einer neuen Liste (siehe oben) oder ein Spezialfall von
emoveEntry (siehe dort). Wegen der besonders bei sehr großen Listen
langen Ausführungszeit sollte RethinkList(...,newList) möglichst
vermieden werden. Um einen einzelnen Eintrag abzuändern, ist es besser,
ihn mit RemoveEntry zu entfernen und nach der Änderung mit InsertEntry
wieder einzufügen.
Folgende Parameter dürfen verändert werden, ohne daß RethinkList benötigt
wird:
SuperList.backPen, SuperList.FontBaseLine, Entry.frontPen, Entry.backPen,
Entry.drawMode, Entry.userFlags, Entry.userData .
Achtung: Wenn Parameter (außer den oben genannten) einer SuperList-
Struktur "von Hand", also nicht über SuperLists-Prozeduren, verändert
werden, so darf keine andere SuperLists-Prozedur aufgerufen werden, bevor
nicht RethinkList ausgeführt wurde. Die Prozedur findet sonst ungültige
Werte vor, was zu einer chaotischen Anzeige und schlimmstenfalls sogar
zum Systemabsturz führen kann. Falls von mehreren Tasks aus auf eine Liste
zugegriffen wird, muß das Programmstück von der Parameterveränderung bis
RethinkList im Forbidden-Status ablaufen.
RethinkList korrigiert soweit als möglich ungültige Werte. Wenn zB. der
aktuelle Anzeigeauschnitt über das Ende der Liste hinaus positioniert
wurde, so wird der Ausschnitt auf die tiefstmögliche Position gesetzt.
Diese Gutmütigkeit hat aber ihre Grenzen.
So sollte man zB. keine Zeiger der Exec.List "verbiegen" oder eine
negative Anzeigenbreite einstellen, weil solche "Scherze" meist unvorher-
sehbare Folgen haben.
RefreshList
-----------
Wie schon der Name sagt, dient diese Prozedur dem Auffrischen, dh. dem
Neu-Anzeigen, des sichtbaren Listenausschnitts. Dies wird in drei Fällen
benötigt:
* wenn die Liste zum ersten mal angezeigt werden soll,
* wenn sich die Liste in einem SimpleRefresh-Window befindet und man
eine Message vom Typ "refreshWindow" erhält oder
* wenn sich die Größe der Anzeigefläche verändert hat. Es ist auch dann
ein Auffrischen erforderlich, wenn die Fläche kleiner geworden ist.
Im Fall 1 und 3 ist auch noch zusätzlich SetProp() erforderlich
(siehe dort).
RedrawEntry
-----------
Zeigt einen Eintrag (Zeile) neu an, sofern sich dieser im gerade
sichtbaren Ausschnitt befindet. Dies ist notwendig, wenn zB. der Text,
die Farbe oder der DrawModus dieses Eintrags verändert wurde. Falls sich
die Länge des Texts verändert hat muß außerdem RethinkList() aufgerufen
werden (siehe oben). Es ist dabei möglich, vorher einen alternativen
Zeichensatz (zB. kursiv) zu setzen (mit Graphics.Set- Font() ), um diesen
Eintrag besonders hervorzuheben. Dieser muß (!) aber die gleiche Zeichen-
größe wie der vorher verwendete haben (FontXsize, FontYsize).
ScrollList
----------
wird verwendet, um die Liste Zeichenweise in eine beliebige Richtung zu
scrollen. Dies wird besonders bei Texteditoren benötigt, oder wenn die
beiden Proportionalscrollgadgets noch mit je zwei Boolgadgets kombiniert
sind (siehe zB. die kleinen Pfeile in den Ecken der Workbench-Windows).
Das Scrolling läuft relativ schnell (weil blitterunterstützt) ab, und es
wird nur der beim Verschieben der BitPlane-Daten freigelegte Abschnitt
neu gezeichnet. Es wird damit möglich, Texteditoren zu bauen, bei denen
man nicht ewig warten muß, wenn man sich mit dem Cursor über den
Windowrand hinausbewegt hat (sowas soll's auch geben!).
Es ist nicht möglich, über das Ende oder vor den Anfang der Liste zu
scrollen. Dies wird automatisch erkannt und abgefangen.
"Dir" gibt die Richtung an, mit der sich das imaginäre Fenster über die
Liste bewegt. "Left" bedeutet also, die sichtbaren Daten werden
eigentlich rechtsverschoben, links wird ein Zeichen mehr sichtbar, rechts
verschwindet eins.
MakeEntry
---------
Bevor irgendetwas angezeigt oder gescrollt werden kann, müssen erst
einmal Einträge in der Liste vorhanden sein. Meistens werden diese
dynamisch alloziert, was am besten mit der Prozedur MakeEntry geschieht.
Es wird ein Zeiger auf einen auf Null endenden String, Vorder- und
Hinergrundfarbe und der gewünschte DrawModus übergeben. MakeEntry
alloziert dann Speicher für den Entry-RECORD und den Text (einschließ-
lich abschließender Null), kopiert den Text in den neuen Speicher und
initialisiert den Entry-RECORD. Dabei wird die Länge des Textes (ohne
Null) im Feld node.pri abgelegt. Will man Einträge anders als mit
MakeEntry erzeugen, so ist es wichtig, dies ebenfalls zu tun, da die
Länge für die weitere Verwaltung der Liste nötig ist.
Die Felder userFlags und userData werden nicht benutzt und können vom
Programmierer für beliebige Zwecke verwendet werden.
Ist nicht mehr genügend freier Speicher vorhanden, wird NIL zurückgegeben.
MakeExtEntry
------------
Mit MakeExtEntry kann ein Eintrag erzeugt werden, der einen beliebigen
Datentyp enthält:
TYPE ExtEntry=RECORD
Node:MinEntry;
Data:IrgendeinTyp;
END;
MakeExtEntry muß nur die Länge der gesammten ExtEntry-Struktur übergeben
werden, damit der erforderliche Speicher alloziert werden kann.
InsertEntry
-----------
wird verwendet, um an der Stelle (Zeile) "Row" den Eintrag "Entry" in die
Liste einzufügen. der Parameter "hidden" besagt, ob der Einfügevorgang
sichtbar (s. Konstante "showIt") oder unsichtbar (hideIt) erfolgen soll.
Dies kann wünschenswert sein, wenn mehere Einträge auf einmal eingefügt
werden sollen. Es wäre umständlich und würde eventuell zu viel Zeit
benötigen, nach jeder eingefügten Zeile die Liste neu anzuzeigen.
Stattdessen erfolgt das einfügen der Zeilen unsichtbar. Erst die letzte
Zeile wird sichtbar eingefügt, womit die gesammte Veränderung sichtbar
wird. Einfügen außerhalb des gerade sichtbaren Ausschnitts der Liste
erfolgt natürlich immer unsichtbar, unabhängig vom Parameter "hidden".
Wird bei "Row" ein negativer Wert oder ein Wert, der hinter dem Ende der
Liste liegt, angegeben, dann wird am Ende der Liste angehängt.
RemoveEntry
-----------
Diese Prozedur entfernt einen Eintrag aus der Liste. "Row" bezeichnet die
Nummer des zu ertfernenden Eintrags (Zeile). Der Parameter "hidden" wird
wie bei InsertEntry gehandhabt. Mit dem Parameter "mustRethink" hat es
folgendes auf sich:
Wird der längste Eintrag aus der Liste entfernt, ändert sich die Gesammt-
breite der Liste, und diese muß mit RethinkList neu bestimmt werden. Dies
wird nicht automatisch durchgeführt, da es Fälle gibt, in denen das
Aufrufende Programm besser weiß, wann dies nötig ist und wann nicht.
Es ist zB. denkbar, daß bei einem Textverarbeitungs- programm alle Zeilen
einer Seite sowieso die gleiche maximale Länge haben (DIN A4), und es
deshalb Performance-Verschwendung wäre, jedesmal RethinkList durch-
zuführen. Wird also bei RemoveEntry festgestellt, daß der entfernte
Eintrag der Längste war, dann wird "mustRethink" TRUE, ansonsten bleibt
es unverändert. Das bedeutet zwar, daß dieses Flag vor dem (ersten von
mehreren) Aufruf(en) gelöscht werden muß, ermöglicht aber eine Art Oder-
Verknüpfung bei mehreren RemoveEntry-Aufrufen hintereinander.
GetEntry
--------
ermöglicht es, die Adresse des Entrys mit der Numer "Row" zu suchen. Falls
der Eintrag vorhanden ist, wird ein Zeiger auf ihn zurückgegeben,
ansonsten ist das Ergebnis NIL.
Es wird darauf hingewiesen, daß diese Suche unter Umständen lange dauern
kann, falls der gesuchte Eintrag nicht im sichtbaren Ausschnitt liegt
(dort wird zuerst gesucht). Besonders bei sehr großen Listen (deutlich
mehr als 1000 Einträge) kann es länger dauern, weil dann die gesammte
Liste durchgegangen wird. Dies gilt im übrigen auch für Insert- und
RemoveEntry, die intern auch diese Prozedur verwenden.
Ich glaube aber, daß dies kein wesentliche Nachteil ist, weil Superlists
wohl meistens für weniger lange Listen verwendet werden wird.
ClickRow
--------
Mit dieser Prozedur kann festgestellt werden, welchen Eintrag der
Benutzer gemeint hat, als er einen Punkt im Window der Liste angeklickt
hat. Es werden die Koordinaten des Zeigers relativ zum Nullpunkt des
RastPorts (des Windows oder Requesters) übergeben. Das Ergebnis ist dann
die Nummer des Eintrags oder -1, falls sich der Mauszeiger außerhalb des
Anzeigebereichs der Liste befand.
GetProp
-------
Wenn festgestellt worden ist, daß der Benutzer eines der Proportional-
gadgets bewegt hat, muß die Stellung der Gadgets ausgelesen und der
gewünschte Ausschnitt der Liste dargestellt werden. GetProp erledigt
ersteres, RefreshList letzteres. Die beiden Prozeduren wurden nicht zu
einer zusammengefaßt, weil es möglich ist, daß der Programmierer
zwischen beiden noch einiges ausführen möchte. Bei der Verwendung von
Proportionalgadgets können nämlich Rundungsfehler auftreten, die sich
darin äußern, daß beim Vor- oder Zurückblättern um eine Seite (Anklicken
der Fläche neben dem Knob im Container) eine Zeile irrtümlicherweise
übersprungen wird. So ist es möglich, vor RefreshList die Parameter des
List-RECORDS entsprechend zu korrigieren (RethinkList nicht vergessen).
Wird darauf verzichtet, ist RethinkList nicht notwendig, dh. RefreshList
kann direkt nach GetProp aufgerufen werden.
SetProp
-------
Hat sich die Größe der Liste oder des Windows verändert, oder wurde mit
ScrollList gearbeitet, dann müssen Stellung (Pot) und Größe (Body) der
(Auto-)Knobs der Proportionalgadgets aktualisiert werden. Dies kann mit
der Prozedur SetProp geschehen, die die Pot- und Body-Variablen der
Gadgets entsprechend dem Verhältnis der sichtbaren Daten zu den
Gesammtdaten einstellt und danach Intuition.ModifyProp() aufruft. Sind
weniger Einträge vorhanden, als das Window hoch ist bzw. alle Einträge
kürzer sind als das Window breit ist, so werden die Body-Werte der
zugehörigen Gadgets auf das Maximum gestellt, dh. der Knob füllt den
ganzen Container.
ClearList
---------
Diese Prozedur entfernt alle Einträge aus einer Liste und gibt den
verwendeten Speicher zurück.
Es ist wichtig, das alle Einträge mit MakeEntry() oder MakeExtEntry()
erzeugt wurden. Sonst können Fehler beim deallozieren des Speichers
auftreten.
AllocProc/DeallocProc
---------------------
Mit diesen Prozedurvariablen können Speicherverwaltungsroutinen eingestellt
werden.
Beispiel:
AllocProc:=Heap.Allocate;
DeallocProc:=Heap.Deallocate;
oder
AllocProc:=MemSystem.Allocate;
DeallocProc:=MemSystem.Deallocate;
-------------------
Viel Spaß !
Bene